import SocketServer, BaseHTTPServer, CGIHTTPServer
import os
from time import ctime, sleep
import sys
from Utilities import *
import Id

__doc__ = """\
Ego CGI Server
Creates a deamonized CGI Server.

usage:
	import Cognition.Pygmund.Ego as Ego
	
	# In Development Mode...
	app = "app.cog"
	
	# Standalone App Mode...
	app = 0
	
	log = True # Set False to disable logging.
	
	Ego.Start(app, log)
"""

__version__ = ("Ego Application Server", 1.0)

class ThreadingServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
	pass

class ForkingServer(SocketServer.ForkingMixIn, BaseHTTPServer.HTTPServer):
	pass

class CGIHandler(CGIHTTPServer.CGIHTTPRequestHandler):
	cgi_directories = [ "/superego" ]

def Start(conf="id/cognition.conf"):
	"""
	Ego.Start(conf="/path/to/cognition.conf", log=True|False)
	
	Creates a EgoServer Daemon.
	"""
	confObj = Id.Init(conf)
	if not conf:
		return -1
	else:
		conf = confObj.Get("EGO")
		log = conf["logging"]
		if log:
			log_conf = confObj.Get("LOGGING")
			LOGGER = Log(log_conf)
		else:
			LOGGER = False
		
		# Print Confirmation...
		print "Starting Ego\n\tDOCROOT: %s\n\tPID DIR: %s\n\tLOG DIR: %s\n\tHOST: %s\n\tPORT: %s\n\tSERVER TYPE: %s\n" % (conf["ego-dir"], conf["pid-dir"], log_conf["dir"], conf["hostname"], conf["port"], conf["server-type"])
		
		if log:
			LOGGER.info("Starting Ego [%s]" % (ctime()))
		
		if log:
			if log_conf["log-daemon"]:
				CreateDaemon(LOGGER)
			else:
				CreateDaemon()
		else:
			CreateDaemon()
		
		if WritePID(os.getpid(), conf["pid-dir"], conf["pid-file"], LOGGER):
			__EgoServer(confObj, conf["ego-dir"], int(conf["port"]), conf["server-type"], conf["hostname"], LOGGER)
		else:
			if log:
				LOGGER.error("Could not write ProcessID [%s]" % (ctime()))
			print "Error: Could not write PID."
			return -1

def Stop(conf="id/cognition.conf"):
	"""
	Ego.Stop(app)
	
	Kills an EgoServer Daemon.
	"""
	confObj = Id.Init(conf)
	if not confObj:
		print "Could not load configuration file."
		return -1
	else:
		conf = confObj.Get("EGO")
	
	print "Stopping Cognition Application Server..."
	
	log = conf["logging"]
	if log:
		log_conf = confObj.Get("LOGGING")
		LOGGER = Log(log_conf)
	else:
		LOGGER = False
	
	if log:
		LOGGER.info("Stopping Ego [%s]" % (ctime()))
	try:
		pid = GetPID(conf["pid-dir"], conf["pid-file"], LOGGER)
		if not pid == 0:
			os.kill(int(pid), SIGKILL)
			ClearPID(conf["pid-dir"], conf["pid-file"], LOGGER)
			if log:
				LOGGER.info("Ego Stopped. [%s]" % ctime())
			print "...Halted."
			return 0
		else:
			if log:
				LOGGER.error("Could not retrieve ProcessID.  Kill server manually.")
			return -1
	except KeyError, e:
		print "Configuration Error:  Could not halt server, please do so manually. (%s)" % e.strerror
		if log:
			LOGGER.error("Could not stop the server. (%s)" % e.strerror)
		return -1
	except OSError, e:
		print "Failed to halt server.  Please do so manually. (%s)" % e.strerror
		if log:
			LOGGER.error("Could not stop the server. (%s)" % e.strerror)
		return -1
	except IOError, e:
		print "Failed to halt server.  Please do so manually. (%s)" % e.strerror
		if log:
			LOGGER.error("Could not stop the server. (%s)" % e.strerror)
		return -1

def Restart(conf="id/cognition.conf"):
	"""
	Ego.Restart(conf="id/cognition.conf")
		Restarts an existing EgoServer Daemon.
	"""
	Stop(conf)
	sleep(1)
	Start(conf)
	return 0

def __EgoServer(confObj=False, doc_root="ego/", port=8080, proc_type="threading", hostname="localhost", LOG=False):
	if not confObj:
		print "EgoServer: Could not load configuration."
		if LOG:
			LOG.error("\tEgo could not load configuration.")
		return -1
	else:
		conf = confObj.Get("EGO")
		if LOG:
			LOG.info("\tEgo Configuration loaded.")
	
	if LOG:
		log_conf = confObj.Get("LOGGING")
		for f in sys.stdout, sys.stderr:
			f.flush()
		logfile = AddSep(log_conf["dir"]) + log_conf["ego"]
		LOG.info("\tLoading server log file:\n\t\tAccess = %s" % (logfile))
	
		if not os.path.exists(logfile):
			so = open(logfile, "wb")
			so.write("\t\tServer Log created @ %s... \n" % ctime())
			so.close()
		so = file(logfile, 'a+')
		os.dup2(so.fileno(), sys.stdout.fileno())
		os.dup2(so.fileno(), sys.stderr.fileno())
	else:
		# If logging is disabled, redirect output to /dev/null or nul
		sys.stdout = os.devnull
		sys.stderr = os.devnull
		
	if LOG:
		LOG.info("\tServer log files loaded")
	if os.path.exists(doc_root):
		doc_root = AddSep(doc_root)
		os.chdir(doc_root)
		if LOG:
			LOG.info("\tChanged to docroot: %s" % doc_root)
	else:
		return -1
	print "Starting Ego Server @ %s" % (ctime())
	if proc_type == "threading":
		serv = ThreadingServer((hostname,port), CGIHandler)
		if LOG:
			LOG.info("\tStarting Threaded Server: %s:%s" % (hostname, port))
		serv.serve_forever()
		
	elif proc_type == "forking":
		serv = ForkingServer((hostname,port), CGIHandler)
		if LOG:
			LOG.info("\tStarting Forking Server: %s:%s" % (hostname, port))
		serv.serve_forever()
		
	else:
		if LOG:
			LOG.info("Invalid server type: %s" % (proc_type))
		print "Invalid Server Mode Specified: %s." % proc_type
		return -1
